package com.forsythia.sns.dao;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.EntityMode;
import org.hibernate.Query;
import org.hibernate.criterion.Example;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.proxy.HibernateProxy;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.forsythia.sns.to.BaseTO;

public class BaseDAOImpl extends HibernateDaoSupport implements BaseDAO {

    protected static final Logger log = Logger.getLogger(BaseDAOImpl.class);

    @Override
    public <T extends BaseTO> T findById(Class<T> clazz, Serializable id) {
        return (T) getSession().get(clazz.getName(), id);
    }

    @Override
    public <T extends BaseTO> List<T> findByExample(T instance) {
        return getSession().createCriteria(instance.getClass().getName()).add(Example.create(instance)).list();
    }

    @Override
    public <T extends BaseTO> List<T> findByProperty(Class<T> clazz, String propertyName, Object value) {
        String queryString = "from " + clazz.getName() + " as model where model." + propertyName + "= ?";
        Query queryObject = getSession().createQuery(queryString);
        queryObject.setParameter(0, value);
        return queryObject.list();
    }

    @Override
    public <T extends BaseTO> T insert(T instance) {
        instance.setCreatedDate(new Date());
        getSession().save(instance);
        return (T) getSession().get(instance.getClass().getName(), getIdValue(instance));
    }
    
    @Override
    public <T extends BaseTO> T update(T instance) {
        instance.setUpdatedDate(new Date());
        getSession().save(instance);
        return (T) getSession().get(instance.getClass().getName(), getIdValue(instance));
    }

    @Override
    public void delete(BaseTO instance) {
        getSession().delete(instance);
    }

    public ClassMetadata getClassMetadata(Class<?> cls) {
        return getSession().getSessionFactory().getClassMetadata(cls);
    }

    public <T extends BaseTO> Serializable getIdValue(T instance) {
        if (instance instanceof HibernateProxy) {
            return (Serializable) ((HibernateProxy) instance).getHibernateLazyInitializer().getIdentifier();
        }
        return (Serializable) getClassMetadata(instance.getClass()).getIdentifier(instance, EntityMode.POJO);
    }

}